﻿using System;
using System.Linq;
using System.Web;
using Umbraco.Core;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Publishing;
using Umbraco.Core.Services;
using config = objectOutlet.Umbraco.ConnectedPages.Config.ConnectedPagesConfig;

namespace objectOutlet.Umbraco.ConnectedPages.Startup
{
	public class RelationsEventHandler : IApplicationEventHandler
	{
		public void OnApplicationInitialized(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
		{ }

		public void OnApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
		{ }

		public void OnApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
		{
			ContentService.Published += ContentService_Published;
		}

		public void ContentService_Published(IPublishingStrategy sender, PublishEventArgs<IContent> e)
		{
			if (e.PublishedEntities == null)
				return;

			try
			{
				var cs = new ContentService();
				var rs = ApplicationContext.Current.Services.RelationService;
				var us = ApplicationContext.Current.Services.UserService;

				var saveAsUserId = config.Current.SaveAsCurrentUser
					? us.GetByUsername(HttpContext.Current.User.Identity.Name).Id
					: 0;

				foreach (var content in e.PublishedEntities)
				{
					if (content.Trashed)
						continue;
					if (!content.IsValid())
						continue;
					if (!rs.IsRelated(content.Id))
						continue;

					var relations = rs.GetByParentOrChildId(content.Id).Where(x => x.RelationType.Alias == config.Current.RelationTypeAlias);

					foreach (var relation in relations)
					{
						var isUpdated = false;
						var relatedContent = cs.GetById(relation.ChildId != content.Id ? relation.ChildId : relation.ParentId);

						foreach (var property in
							from property in content.Properties.Where(property => relatedContent.HasProperty(property.Alias))
								let propertyValue = property.Value == null ? string.Empty : property.Value.ToString()
								let relatedPropertyValue =
									relatedContent.GetValue(property.Alias) == null
										? string.Empty
										: relatedContent.GetValue(property.Alias).ToString()
							where !propertyValue.Equals(relatedPropertyValue) &&
								!config.Current.IgnorePropertyAlias.Contains(property.Alias)
							select property)
						{
							relatedContent.SetValue(property.Alias, property.Value);
							isUpdated = true;
						}

						if (!isUpdated)
							continue;

						if (relatedContent.Published)
						{
							cs.SaveAndPublishWithStatus(relatedContent, saveAsUserId, false);
						}
						else
						{
							cs.Save(relatedContent, saveAsUserId, false);
						}
					}
				}
			}
			catch (Exception ex)
			{
				LogHelper.Error(GetType(), "An error occured while applying property values between Connected Pages", ex);
				if (config.Current.RethrowExceptions)
					throw;
			}
		}
	}
}